package test;

import mandelbrotmw.*;
import masterworker.*;

import mpi.MPI;
import mpi.Status;

import datastructure.*;

public class MandelbrotMW {
	
	static int N = 2;
	static int NPIXELS = 50;
	
	public static void main (String[] args){
		doMandelbrot(args, 2, 2, 4, 50);
	}	
	
	public static void doMandelbrot (String[] args, double x0, double y0, double size, int maxiter) 
	{
		int nprocs;
		int myid;
		int returnval;
		
		double realmin = -N;
		double realmax = N;
		double imagemin = N;
		double imagemax = -N;
		
		int width = NPIXELS;
		int height = NPIXELS;
		
		
		MandelbrotMaster master = new MandelbrotMaster();
		
		
		/* Init MPI by starting master */	

		master.startMPI(args);
		myid = master.getID();
		nprocs = master.getNumberOfProcessors();
		
		/* Set up number of workers */
		master.setNumberOfWorker(nprocs-1);
		
		realmax = x0 + size;
		realmin = x0 - size;
		imagemax = y0 + size;
		imagemin = y0 - size;
		
		/* Call master or worker code as appropriate */
		
		if (myid == 0){
			callMaster(master.getNumberOfWorkers(), master, width, height, realmin, realmax, imagemin, imagemax, maxiter);
			
		}
		else {
			callWorker(myid, width, height, realmin, realmax, imagemin, imagemax, maxiter);
		}
		MPI.Finalize();
	}	
	
	

	/* Master */
	public static void callMaster(int nworkers, MandelbrotMaster master, int width, int height, double realmin,
			double realmax, double imagemin, double imagemax, int maxiter){
		
		int masterID = 0;
		int this_row;

		long[] color = new long[2];
		color[0] = 18; //min
		color[1] = 84; //max
		double start_time;
		double end_time;
		double[] timempi = new double[2];
		
		
		/* Start timing */
		master.startTime();
		
		System.out.println("Min color = " + color[0] + " Max color =" + color[1]);
		
		/* Broadcast value */
		DataStructure colordata = new DataStructure(color);
		colordata.BcastLong(masterID);
		
		/* End timing */
		master.endTime();
		timempi = master.getMPITime();
		
		start_time = timempi[0];
		end_time = timempi[1];
		
		/* Do parallel */
		master.doWork(width, nworkers, height);
		
		/* Print out */
		System.out.println("\n Number of workers = " + nworkers);
		System.out.println("\n Center = (" + (realmax + realmin)/2 + "," + (imagemax + imagemin)/2 +
				"), size = " + (realmax - realmin)/2);
		System.out.println("\n Maximum iteration = " + maxiter);
		System.out.println("\n Execution time = " + (end_time-start_time));
		
	}
	
	/* Worker */
	public static void callWorker(int myID, int width, int height, double realmin,
			double realmax, double imagemin, double imagemax, int maxiter){
		
		MandelbrotWorker worker = new MandelbrotWorker(myID);
		
		int master = 0;
		double scale_real;
		double scale_image;
		double scale_color;

		long[] color_value = {1,1}; //Initiating		
		
		/* Receive broadcast value */
		
		DataStructure color_data = new DataStructure(color_value);
		color_data.BcastLong(master);
		
		System.out.println("Min color = " + color_value[0] + " Max color =" + color_value[1]);
		
		/* Compute factor for computational scaling */
		
		scale_real = (double)(realmax - realmin)/(double)(width);
		scale_image = (double)(imagemax - imagemin)/(double)(height);
		
		System.out.println("\n Scale real = " + scale_real + " Scale image =" + scale_image);
		
		/* Compute factor for color scaling */
		scale_color = (double)(color_value[1] - color_value[0])/(double)(maxiter -1);
		System.out.println("\n Scale color = " + scale_color);
		
		/* While master is still sending work call doWork method to process */		
		worker.doWork(myID, N, width, height, realmin, realmax, 
				imagemin, imagemax, maxiter, scale_real, scale_image, scale_color, color_value);
	}
}
